package com.pivots.dde;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

import org.apache.commons.lang.StringUtils;

import alibobo.util.date.DateUtils;
import alibobo.util.io.file.FileUtils;

import com.javaparts.dde.AsyncCompletedEvent;
import com.javaparts.dde.Conversation;
import com.javaparts.dde.DDEClient;
import com.javaparts.dde.DDEEvent;
import com.javaparts.dde.DDEEventListener;
import com.javaparts.dde.ItemChangedEvent;


public class DDEItemFill {

	String subpath = "";
	final Map<String, Map<String, Boolean>> updateLog = new HashMap<String, Map<String, Boolean>>();
	final Map<String, Map<String, String>> updateValues = new HashMap<String, Map<String, String>>();
	final Map<String, Object> miscMap = new HashMap<String, Object>();

	boolean enablePrint = false;
	Queue<String> itemToAdd = new java.util.concurrent.ConcurrentLinkedQueue<String>();

	DDEClient client = DDEClient.getInstance();
	Conversation conversation = null;

	// ------------------>

	List<String> tempRec = new ArrayList<String>(25000);
	Queue<List<String>> listQueue = new ConcurrentLinkedQueue<List<String>>();
	Date lastSaveTime = new Date();

	public int getAccumCount() {
		return tempRec.size();
	}

	public int getItemToAddCount() {
		return itemToAdd.size();
	}

	public long getNoDataGap() {
		return new Date().getTime() - lastNewRecTime;
	}

	long lastNewRecTime = new Date().getTime();

	public void PutValues(String code, String item, String value) {
		//
		if (tempRec.size() > 20000) {
			listQueue.add(tempRec);
			tempRec = new ArrayList<String>();
		}

		Date d = new Date();
		lastNewRecTime = d.getTime();

		StringBuffer sb = new StringBuffer();
		sb.append("[");
		sb.append(DateUtils.toYYYYMMDDhhmmss_NoSlash(d, false));
		sb.append("]\t[");
		sb.append(code);
		sb.append("]\t[");
		sb.append(item);
		sb.append("]=");
		sb.append(value);
		tempRec.add(sb.toString());

	}

	public Integer getTicker() {
		return (Integer) miscMap.get("count");
	}

	public Integer getUpdatedCount() {
		return (Integer) miscMap.get("updatedCount");
	}

	public Integer getTotalItem() {
		return (Integer) miscMap.get("totalItem");
	}

	public Map getmiscMap() {
		return miscMap;
	}

	public Map<String, Map<String, String>> getResult() {
		return updateValues;
	}

	boolean ddeInited=false;
	public boolean isDdeInited() {
		return ddeInited;
	}

	public DDEItemFill() {
		try {
			client.addDDEEventListener(new DDEEventListener() {

				@Override
				public void onAsyncCompleted(AsyncCompletedEvent arg0) {

					System.out.println("================onAsyncCompleted");
					System.out.println(arg0.getTransactionId());
					if (arg0.getTransactionResult() == null) {
						System.out.println("NULL");
						return;
					}
					String s = new String(arg0.getTransactionResult());
					System.out.println(s);

				}

				@Override
				public void onDisconnect(DDEEvent arg0) {
					System.out.println("disconnected");

				}

				@Override
				public void onItemChanged(ItemChangedEvent event) {

					try {
						String itemName = event.getItemName();
						String itemValueStr = new String(event.getItemValue());
						if (StringUtils.isBlank(itemValueStr)) {

						} else {
							if (miscMap.containsKey("count")) {
								Integer c = (Integer) miscMap.get("count");
								miscMap.put("count", c + 1);

							} else {
								miscMap.put("count", 1);
							}
							int pos = itemName.indexOf(".");
							String code = itemName.substring(0, pos);
							String item = itemName.substring(pos + 1);
							updateValues.get(code).put(item, itemValueStr);

							PutValues(code, item, itemValueStr);

							if (enablePrint)
								System.out.println(code + "[" + item + "]="
										+ itemValueStr);

							if (updateLog.get(code).get(item).equals(false)) {
								updateLog.get(code).put(item, true);
								if (miscMap.containsKey("updatedCount")) {
									Integer i = (Integer) miscMap
											.get("updatedCount");
									miscMap.put("updatedCount", i + 1);
								} else {
									miscMap.put("updatedCount", 1);
								}

							}
						}

					} catch (Exception e2) {
						e2.printStackTrace();
					}
				}
			});

			conversation = client.connect("TS", "KS");
			conversation.setDefaultTimeout(6000);
			ddeInited=true;
		} catch (Exception e) {
			e.printStackTrace();			
		}

	}

	public boolean batchAddItem() {
		if (itemToAdd.size() == 0)
			return false;
		int i = 0;
		while (i < 10) {
			i++;
			String s = itemToAdd.poll();
			if (s == null)
				break;
			try {
				conversation.startAdvice(s);
			} catch (Exception e) {
				e.printStackTrace();
				System.err.println("Add Fail:" + s);
				itemToAdd.add(s);
				break;
			}
		}
		System.out.println("\t\t\t\titemToAdd:" + itemToAdd.size());
		return itemToAdd.size() > 0;

	}

	public void RequestItem(String code, String field) {
		if (updateLog.get(code) == null) {
			updateLog.put(code, new HashMap<String, Boolean>());
		}
		if (updateValues.get(code) == null) {
			updateValues.put(code, new HashMap<String, String>());
		}
		itemToAdd.add(code + "." + field);

		if (miscMap.get("totalItem") == null)
			miscMap.put("totalItem", 1);
		else {
			Integer it = (Integer) miscMap.get("totalItem");
			miscMap.put("totalItem", it + 1);
		}

	}

	public void RequestItems(List<String> codes, List<String> fields) {

		Integer totalItem = (Integer) miscMap.get("totalItem");
		if (totalItem == null)
			totalItem = 1;

		for (String code : codes) {
			Map<String, Boolean> m0 = new HashMap<String, Boolean>();
			Map<String, String> m1 = new HashMap<String, String>();
			for (String field : fields) {
				m0.put(field, false);
				m1.put(field, "N/A");
				itemToAdd.add(code + "." + field);
				totalItem++;
			}
			updateLog.put(code, m0);
			updateValues.put(code, m1);
		}
		miscMap.put("totalItem", totalItem);

	}

	public boolean isEnablePrint() {
		return enablePrint;
	}

	public void setEnablePrint(boolean enablePrint) {
		this.enablePrint = enablePrint;
	}

	public int SaveRec(boolean force) {
		int sz = listQueue.size();
		List<String> ll = listQueue.poll();
		if (ll == null) {
			// try force save.
			if (tempRec.size() > 0) {
				if (force) {
					listQueue.add(tempRec);
					tempRec = new ArrayList<String>();
				} else {
					Date d = new Date();
					long diff = d.getTime() - lastSaveTime.getTime();
					if (diff > 60000) {
						listQueue.add(tempRec);
						tempRec = new ArrayList<String>();
					}
				}
				sz = listQueue.size();
				ll = listQueue.poll();
			}
		}
		if (ll == null)
			return sz;

		try {
			lastSaveTime = new Date();
			String ds = DateUtils.toYYYYMMDDhhmmss_continue(new Date(), false);
			FileUtils.writeStringsToFile(ll, getStorePath() + ds + ".txt");
			ll.clear();

		} catch (Exception e) {
			// TODO: handle exception
		}
		return sz;
	}

	public String getSubpath() {
		return subpath;
	}

	protected String getStorePath() {
		if (StringUtils.isNotBlank(subpath)) {
			return "d:\\bid5\\data\\" + subpath + "\\"+DateUtils.toYYYYMMDD_NoSlash(new Date(),false)+"\\";
		}
		return "d:\\";
	}

	public void setSubpath(String subpath) {
		this.subpath = subpath;
		if (StringUtils.isNotBlank(subpath)) {
			String path = getStorePath();
			File f = new File(path);
			f.mkdirs();
		}
	}

}
